import java.util.*;

/**
 * @author LKQ
 * @date 2022/5/9 15:38
 * @description 动态规划
 */
public class Solution {
    public static void main(String[] args) {
        Solution solution = new Solution();
        List<String> board = new ArrayList<>();
        board.add("E23");
        board.add("2X2");
        board.add("12S");
        solution.pathsWithMaxScore(board);
    }
    int n;
    int mod = (int) 1e9 + 7;
    public int[] pathsWithMaxScore(List<String> board) {
        n = board.size();
        // f[i][j] 代表到达 i,j 位置的最大得分
        int[][] f = new int[n][n];
        // cnt[idx] 代表 到达位置 i,j 的方案数
        int[] cnt = new int[n * n];
        cnt[0] = 1; f[0][0] = 0;

        char[][] bo = new char[n][n];
        for (int i = 0; i < n; i++) {
            bo[i] = board.get(i).toCharArray();
        }
        // 初始化，第一行和第一列的值
        for (int i = 1; i < n; i++) {
            if (bo[i][0] == 'X') {
                break;
            }
            f[i][0] =  f[i-1][0] + bo[i][0] - '0' ;
            cnt[getIdx(i, 0)] = 1;
        }
        for (int i = 1; i < n; i++) {
            if (bo[0][i] == 'X') {
                break;
            }
            f[0][i] =  f[0][i-1] + bo[0][i] - '0';
            cnt[getIdx(0, i)] = 1;
        }
        // 反过来从(0,0) 到 (n-1,n-1)
        for (int i = 1; i < n; i++) {
            for (int j = 1; j < n; j++) {
                if (bo[i][j] != 'X') {
                    int down = f[i-1][j], right = f[i][j-1], rightDown = f[i-1][j-1];
                    int max = Math.max(down, Math.max(right, rightDown));
                    f[i][j] = max + (bo[i][j] == 'S' ? 0 : bo[i][j] - '0');
                    if (max == down) {
                        cnt[getIdx(i, j)] += cnt[getIdx(i-1, j)] % mod;
                    }
                    if (max == right) {
                        cnt[getIdx(i, j)] += cnt[getIdx(i, j -1)] % mod;
                    }
                    if (max == rightDown) {
                        cnt[getIdx(i, j)] += cnt[getIdx(i-1, j-1)] % mod;
                    }
                }else {
                    f[i][j] = Integer.MIN_VALUE;
                }
            }
        }
        int idx = n * n - 1;
        // 最后需要mod一下，因为都是先mod后加起来，最后一次答案并没有mod
        return cnt[idx] == 0 ? new int[] {0, 0} : new int[] {f[n-1][n-1], cnt[idx] % mod};
    }

    int getIdx(int i, int j) {
        return i * n + j;
    }
    int[] parseIdx(int idx) {
        return new int[] {idx / n, idx % n};
    }
}
